/*
 * @Description: 命名空间
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-05-06 18:41:05
 * @LastEditTime: 2021-05-20 16:03:50
 */


/**
 *  定义
 *  “命名空间”在1.5版本之前叫“内部模块”，是相对于“外部模块”而命名的。
 *  命名空间是为了与 ECMAScript 2015里的术语保持一致，推荐的写法 namespace X {}
 *  命名空间实际上就是ts文件内部的模块。内部模块的作用是为了记录对象类型的同时还不用担心与其它对象产生命名冲突,这样就避免了全局命名的混乱。
 */
namespace Validation {
	
	// 命名空间内的接口需要导出 才能在外部访问。外部需要什么就导出什么
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

// Some samples to try
let strings = ["Hello", "98052", "101"];

/*
 命名空间的使用
 命名空间内的变量需要【命名空间.导出的变量名】来使用
 */
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();


/**
 * 命名空间的合并
 * 由于逻辑的复杂度，我们可能需要把同一个命名空间分到不同的文件中，那么最终我们需要合并不同的文件中相同的命名空间
 * 外部的命名空间文件引用不适用导入导出，而是使用特殊的注释标签`/// <reference path="Validation.ts" />`
 * 命名空间文件之间的依赖关系也是使用注释标签来保持关联
 */
/* --------------- Validation.ts-------------------- */
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}
/* --------------------------------------------------- */

/* ------------------LettersOnlyValidator.ts----------------- */
/// <reference path="Validation.ts" />
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}
/* ----------------------------------------------------------- */

/* ----------------------Test.ts----------------------------- */
/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
/* ----------------------------------------------------------- */

/**
 * 当涉及到多文件时，我们必须确保所有编译后的代码都被加载了。 我们有两种方式。
 * > 把所有的输入文件编译为一个输出文件，需要使用--outFile标记：`tsc --outFile sample.js Test.ts`
 */

/**
 * 命名空间别名
 * 使用import关键字可以为命名空间内的变量创建别名，注意这种方式区别与导入模块
 */
namespace Shapes {
    export namespace Polygons {
        export class Triangle { }
        export class Square { }
    }
}
import polygons = Shapes.Polygons;
let sq = new polygons.Square()


// 与declare
declare const aaa {
	export namespace bbb {
		export interface ccc{
			a:string
		}
	}
}